﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Text.RegularExpressions;
using Microsoft.Win32;
using System.IO;

namespace FCS.SequenceDesigner
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Dictionary<string, Valve> _valves = new Dictionary<string, Valve>();

        List<Valve> _on = new List<Valve>();
        List<Valve> _off = new List<Valve>();
        List<Valve> _listOfAllValves = new List<Valve>();
        String _sequence;

        public MainWindow()
        {
            InitializeComponent();
            CreateDots();
            CreateLabels();
            ResetValveLists();
        }

        private void ResetValveLists()
        {          
            _sequence = "";

            foreach (Valve v in _listOfAllValves)
            {
                Fountain_ValveChanged(v.Name, false);
            }

            _on.Clear();
            _off.Clear();
            foreach (Valve v in _listOfAllValves)
            {
                _off.Add(v);
            }

        }

        private void CreateLabels()
        {
            delayLabel.Content = "1 Second Delay";

            #region Valves Labels
            // create the labels that run above the valves
            for (int i = 0; i < 12; i++)
            {
                Label l = new Label();
                l.FontSize = 20;
                l.Content = i + 1;

                if (i == 10)
                    l.Content = "C";
                else if (i == 11)
                    l.Content = "R";

                ValveCanvas.Children.Add(l);
                if (i != 9)
                    Canvas.SetLeft(l, 39 + 50 * i);
                else if (i == 9)
                    Canvas.SetLeft(l, 34 + 50 * i);


                Canvas.SetTop(l, 5);
            }

            // create the H and V labels to the left of the valve markers
            Label h = new Label();
            Label v = new Label();

            h.FontSize = 20;
            h.Content = "H";
            ValveCanvas.Children.Add(h);
            Canvas.SetLeft(h, 7);
            Canvas.SetTop(h, 30);

            v.FontSize = 20;
            v.Content = "V";
            ValveCanvas.Children.Add(v);
            Canvas.SetLeft(v, 7);
            Canvas.SetTop(v, 80);

            // create N label for north end mister
            Label n = new Label();
            n.FontSize = 20;
            n.Content = "N";
            ValveCanvas.Children.Add(n);
            Canvas.SetLeft(n, 7);
            Canvas.SetTop(n, 130);
            #endregion

            #region Winter Mister Labels
            // create labels to indicate winter mister valve
            Label m = new Label();
            m.FontSize = 20;
            m.Content = "M";
            ValveCanvas.Children.Add(m);
            Canvas.SetLeft(m, 7);
            Canvas.SetTop(m, 230);

            // create labels for north and south mister
            Label mn = new Label();
            mn.FontSize = 20;
            mn.Content = "N";
            ValveCanvas.Children.Add(mn);
            Canvas.SetLeft(mn, 37);
            Canvas.SetTop(mn, 260);

            Label ms = new Label();
            ms.FontSize = 20;
            ms.Content = "S";
            ValveCanvas.Children.Add(ms);
            Canvas.SetLeft(ms, 89);
            Canvas.SetTop(ms, 260);

            #endregion

            #region Weir and Bollard Labels
            // create the W label to the left of the weir markers
            Label w = new Label();
            w.FontSize = 20;
            w.Content = "W";
            ValveCanvas.Children.Add(w);
            Canvas.SetLeft(w, 7);
            Canvas.SetTop(w, 180);

            #endregion
        }

        private void CreateDots()
        {
            Action<Valve> AddValve = (Valve v) => { _valves.Add(v.Name, v); _listOfAllValves.Add(v); };

            AddValve(new Valve("V1", 50, 100));
            AddValve(new Valve("V2", 100, 100));
            AddValve(new Valve("V3", 150, 100));
            AddValve(new Valve("V4", 200, 100));
            AddValve(new Valve("V5", 250, 100));
            AddValve(new Valve("V6", 300, 100));
            AddValve(new Valve("V7", 350, 100));
            AddValve(new Valve("V8", 400, 100));
            AddValve(new Valve("V9", 450, 100));
            AddValve(new Valve("V10", 500, 100));
            AddValve(new Valve("VR", 550, 100));
            AddValve(new Valve("VC", 600, 100));

            AddValve(new Valve("H1", 50, 50));
            AddValve(new Valve("H2", 100, 50));
            AddValve(new Valve("H3", 150, 50));
            AddValve(new Valve("H4", 200, 50));
            AddValve(new Valve("H5", 250, 50));
            AddValve(new Valve("H6", 300, 50));
            AddValve(new Valve("H7", 350, 50));
            AddValve(new Valve("H8", 400, 50));
            AddValve(new Valve("H9", 450, 50));
            AddValve(new Valve("H10", 500, 50));
            AddValve(new Valve("HR", 550, 50));
            AddValve(new Valve("HC", 600, 50));

            AddValve(new Valve("N0", 50, 150));

            AddValve(new Valve("MN", 50, 250));
            AddValve(new Valve("MS", 100, 250));

            AddValve(new Valve("W1", 50, 200));
            AddValve(new Valve("W2", 100, 200));
            AddValve(new Valve("W3", 150, 200));

            foreach (Valve valve in _valves.Values)
            {
                ValveCanvas.Children.Add(valve.Dot);
                Canvas.SetLeft(valve.Dot, valve.X - Valve.DotSize / 2);
                Canvas.SetTop(valve.Dot, valve.Y - Valve.DotSize / 2);
            }
        }

        /// <summary>
        /// When the user presses down with their finger (i.e. mouse) the valve should be toggled
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Valve v = GetValveFromPoint(e);
            if (v != null)
            {
                List<string> cmd = new List<string>();
                cmd.Add(v.Name);
                string state = !v.State ? "ON" : "OFF";
                
                Fountain_ValveChanged(v.Name, !v.State);
            }
        }

        void Fountain_ValveChanged(string valve, bool newState)
        {
            // We need to update our screen
            Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
            {
                if (_valves.ContainsKey(valve))
                    _valves[valve].State = newState;
            }));

            Valve v = _valves[valve];

            if (_on.Contains(v))
            {
                _on.Remove(v);
                _off.Add(v);
            }
            else
            {
                _on.Add(v);
                _off.Remove(v);
            }
        }

        // <summary>
        /// Find the valve that is closest to where the mouse is
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        private Valve GetValveFromPoint(MouseEventArgs e)
        {
            Point point = e.GetPosition(ValveCanvas);

            // Let's find the closest point to our tap
            Valve valve = _valves.Values.OrderBy(v => v.GetDistanceFromPointSquared(point)).First();

            // Have a minimum closeness
            if (valve.GetDistanceFromPointSquared(point) < Math.Pow(Valve.DotSize + 20, 2))
                return valve;
            else
                return null;
        }

        private void DelayValueChange(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (delayLabel == null || delaySlider == null)
                return;

            delayLabel.Content = delaySlider.Value.ToString() + " second delay";
        }

        private void newButton_Click(object sender, RoutedEventArgs e)
        {
            ResetValveLists();
        }

        private void Next_Click(object sender, RoutedEventArgs e)
        {
            _sequence += "ON ";
            foreach(Valve v in _on)
            {
                _sequence += v.Name + " ";
            }

            _sequence += "\nOFF ";
            foreach(Valve v in _off)
            {
                _sequence += v.Name + " ";
            }
            _sequence += "\n" + delaySlider.Value + "\n";
        }

        private void saveAsButton_Click(object sender, RoutedEventArgs e)
        {
            String strFileName;

            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "pattern (*.ptrn)|*.ptrn|All files (*.*)|*.*";
            dialog.Title = "Save sequence as...";

            dialog.ShowDialog();

            strFileName = dialog.FileName;

            // return if the filename is empty (user didn't choose anything)
            if (strFileName == String.Empty)
                return;

            // Write out to file
            StreamWriter sr = new StreamWriter(strFileName);
            sr.Write(_sequence);
            // after writing the sequence, write the off command
            sr.Write("OFF ");
            foreach (Valve v in _listOfAllValves)
            {
                sr.Write(v.Name + " ");
            }

            sr.Close();
            sr.Dispose();
            
            ResetValveLists();
        }
    }
}
